package org.longteng.mobileluck.algorithm.service.impl;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.longteng.core.utils.ChineseYijingNumUtil;
import org.longteng.core.utils.StringExUtils;
import org.longteng.mobileluck.algorithm.bean.MobileNumAuspiciousTable;
import org.longteng.mobileluck.algorithm.bean.MobileNumAuspiciousVo;
import org.longteng.mobileluck.algorithm.bean.MobileNumFortuneTable;
import org.longteng.mobileluck.algorithm.dao.MobileNumAuspiciousDao;
import org.longteng.mobileluck.algorithm.service.CartPlateNumAuspiciousService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;

/**
 * 车牌号码吉祥如意计算service实现
 * <br>所有的自然数是没有吉凶的，但它与某个体结合产生关联时，就会有影响，才生吉凶。数的含意很多，简单地说有阴阳的含意，即单数为阳，双数为阴。
 * <br>有五行的含意，即1、6为水、2、7为火、3、8为木、4、9为金、5、0为土。有方位的含意，即1、6为北方、2、7为南方、3、8为东方、4、9为西方、5、0为居中。
 * <br>有卦象的含意，即三个数、四个数、五个数都可成卦，每个卦都蕴涵有许多相关事宜。
 * <br>卦象无不良:卦象的好坏，需要一定的易学专业知识才能判断，但用以下简单方法可避开一些不良的卦象。
 * <br>如所有数字的和不要为6、18、14、16、19、22、26、29、32，因为它们的卦象分别为：坎、天地否、天雷无妄、天水讼、乾（常人不用）、兑、泽水困、泽天夬、火泽癸，这些卦象都不是很理想。
 * <br>所谓阴阳互见，就是车牌号的数字要有单有双，不能全单或全双，因为《易》理认为，孤阴不生，独阳不长
 * <br>所谓三才得配是指天、地、人三者的关系要处理恰当，人生活在天地之间，一定要尊天敬地。如果三位数，其中间数不要全大于前后的数，如果四位数字，其中间两位数不要全大于前后的数，如果五位数，其中间的一位数不要全大于两边的数。
 * @author hymn.com
 */
@Slf4j
@Service
public class CartPlateNumAuspiciousServiceImpl implements CartPlateNumAuspiciousService {
    private MobileNumAuspiciousDao mobileNumAuspiciousDao;
    @Autowired
    @Qualifier(value="mobileNumAuspiciousTable")
    public void setMobileNumAuspiciousDao(MobileNumAuspiciousDao mobileNumAuspiciousDao) {
        this.mobileNumAuspiciousDao = mobileNumAuspiciousDao;
    }

    /**
     * 根据完整车牌号计算出解释批注测吉凶
     *
     * @param cartPlateNum
     * @return
     */
    @Override
    public MobileNumAuspiciousVo parseCartNumLuck(String cartPlateNum) {
        int mobileLuck = ChineseYijingNumUtil.yijingNumberCalculate(cartPlateNum);
        // 跟据车牌号数理得出解释批注测吉凶
        MobileNumAuspiciousTable mobileNumAuspiciousTable = mobileNumAuspiciousDao.getAuspiciousEntity(mobileLuck);
        if (mobileNumAuspiciousTable != null) {
            mobileNumAuspiciousTable.setMobilePhoneNumber(cartPlateNum);
        } else {
            log.warn("根据车牌号{}数理{}，未找到对应解释批注。", cartPlateNum, mobileLuck);
        }

        // 跟据车牌号数理得出吉祥运势测吉凶,五行含意、单双比,总和卦象、三才得配
        MobileNumFortuneTable mobileNumFortuneTable = MobileNumFortuneTable.parseCartNumFortune(cartPlateNum);
        mobileNumFortuneTable.setMobileNum(mobileLuck);
        MobileNumAuspiciousVo mobileNumAuspiciousVo = new MobileNumAuspiciousVo(mobileNumAuspiciousTable, mobileNumFortuneTable);
        return mobileNumAuspiciousVo;
    }

    /**
     * 根据完整车牌号集合计算出解释批注测吉凶
     *
     * @param cartPlateNum
     * @return
     */
    @Override
    public List<MobileNumAuspiciousVo> parseCartNumsLuck(String... cartPlateNum) {
        List<MobileNumAuspiciousVo> list = new ArrayList<>();
        for (String cPlateNum : cartPlateNum) {
            MobileNumAuspiciousVo mobileNumAuspiciousVo = this.parseCartNumLuck(cPlateNum);
            list.add(mobileNumAuspiciousVo);
        }

        return list;
    }

    /**
     * 根据完整车牌号集合计算出解释批注测吉凶
     *
     * @param cartPlateNumList
     * @return
     */
    @Override
    public List<MobileNumAuspiciousVo> parseCartNumsLuck(List<String> cartPlateNumList) {
        List<MobileNumAuspiciousVo> list = new ArrayList<>();
        if (cartPlateNumList != null) {
            list = this.parseCartNumsLuck(cartPlateNumList.toArray(new String[cartPlateNumList.size()]));
        }
        return list;
    }

    /**
     * 给出吉祥自编车牌号
     * <br>普通燃油车辆是7位,新能源车辆号牌是8位(第1位省简称，第2位省市排的字母)
     *
     * @param setChars 包括的字母
     * @param setNums  包括的数字，可不指定就分析全部计算吉祥的号
     * @param prefix 省市简称前缀
     * @param cartType 车类型，0燃油，1新能源
     * @return
     */
    @Override
    public List<String> markLuckCartNums(String setChars, String setNums, String prefix, int cartType) {
        // TODO 生成车牌的排序组合 Permutation Combination
        if(setChars == null) {
            setChars = "";
        }
        if(StringExUtils.isEmpty(setNums)) {  // 不指定就全部数字生成
            setNums = "0123456789";
        }
        char[] letters = setChars == null ? new char[]{} : setChars.toCharArray();
        String[] carChars = StringExUtils.toStrArray(letters);
        int[] numbersChar = setNums == null ? new int[]{} : StringExUtils.toNumberArray(setNums);
        int len = cartType == 0 ? 5 : 6;  // 普通燃油车辆是7位,新能源车辆号牌是8位(第1位省简称，第2位省市排的字母)

        List<String> outCharNumList = new ArrayList<>();
        List<String> outNumList = new ArrayList<>();
        StringExUtils.numberCombination(carChars, new int[]{}, "", carChars.length, true, outCharNumList);
        // 数字组合可重复
        StringExUtils.numberCombination(new String[]{}, numbersChar, "", len-carChars.length, false, outNumList);
        List<String> luckNumList = new ArrayList<>();
        List<String> luckNumList2 = new ArrayList<>();
        for (String carNum : outNumList) {
            int mobileLuck = ChineseYijingNumUtil.yijingNumberCalculate(carNum);
            // 跟据车牌号数理得出解释批注测吉凶
            MobileNumAuspiciousTable mobileNumAuspiciousTable = mobileNumAuspiciousDao.getAuspiciousEntity(mobileLuck);
            if(mobileNumAuspiciousTable != null
                    && StringUtils.indexOf(mobileNumAuspiciousTable.getLuckStatus(),"吉") > -1) {
                for (String sCharNum : outCharNumList) {
                    // 吉的放前面，半吉的放后面
                    if(StringUtils.equalsAny(mobileNumAuspiciousTable.getLuckStatus(),"吉","大吉")) {
                        luckNumList.add((prefix == null ? "" : prefix) + sCharNum + carNum);
                    } else {
                        luckNumList2.add((prefix == null ? "" : prefix) + sCharNum + carNum);
                    }
                }  // for end
            } else {
                if(log.isDebugEnabled()) {
                    log.debug("排队不吉祥的车牌排列号:{}", carNum);
                }
            }
        }  // for end

        luckNumList.addAll(luckNumList2);
        return luckNumList;
    }

}
